package com.ddfeiyu.redis.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
public class RedisQueueUtil {

    private static final long TIMEOUT =  2L;

    /**
     * 链路id映射的业务id
     */
    public static final String DDFEIYU_TID_MAP_BUSID_KEY = "ddfeiyu:tid:map:busId:";


    /**
     * 业务id映射链路id
     */
    public static final String DDFEIYU_BUSID_MAP_TID_KEY = "ddfeiyu:busId:map:tid";

    /**
     * 日志队列
     */
    public static final String DDFEIYU_TRACE_LOG_QUEUE_KEY = "ddfeiyu:trace:loglist:tid:";

    /**
     * 服务注册信息： ip:port
     */
    public static final String DDFEIYU_SERVER_QUEUE = "ddfeiyu:server:queue";


    private StringRedisTemplate redisTemplate ;

    public RedisQueueUtil(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate ;
    }


    /**
     * 绑定traceId到busId
     * @param traceId
     * @param busId
     */
    public void bindTraceAndReq(String traceId, String busId){
        bindBusId2TraceId(busId, traceId);
        bindTraceId2BusId(traceId, busId);
        log.info("---[1]绑定traceId和busId ,busId:[ {} ], traceId:[ {} ]",busId , traceId);
    }

    /**
     * 绑定busId 到 traceId
     * @param busId
     * @param traceId
     */
    private void bindBusId2TraceId(String busId, String traceId){
        String key = makeFullKey(DDFEIYU_BUSID_MAP_TID_KEY, busId);
        setForString(key, traceId, TIMEOUT , TimeUnit.HOURS);
    }

    /**
     * 绑定 traceId 到 busId
     * @param traceId
     * @param busId
     */
    private void bindTraceId2BusId(String traceId, String busId){
        String key = makeFullKey(DDFEIYU_TID_MAP_BUSID_KEY, traceId);
        setForString(key, busId, TIMEOUT , TimeUnit.HOURS);
    }

    /**
     * 根据 busId 查询 TraceId
     * @param busId
     * @return
     */
    public String getTraceIdByBusId(String busId){
        String key = makeFullKey(DDFEIYU_BUSID_MAP_TID_KEY, busId);
        return getForString(key);
    }

    /**
     * 根据 TraceId  查询 busId
     * @param traceId
     * @return
     */
    public String getBusIdByTraceId(String traceId){
        String key = makeFullKey(DDFEIYU_TID_MAP_BUSID_KEY, traceId);
        return getForString(key);
    }

    /**
     * 入队
     * @param traceId 链路id
     * @param list
     */
    public long enqueue(String traceId, List<String> list){
        String key = makeFullKey(DDFEIYU_TRACE_LOG_QUEUE_KEY, traceId);
        long len = leftPushAll(key, list);
        expire(key, TIMEOUT, TimeUnit.HOURS);
        log.info("---[2]日志入队 traceId:[ {} ], key:[ {} ] -> log:[ {} ]", traceId , key , list);
        return len;
    }



    /**
     * 出队
     * @param traceId 链路id
     */
    public String dequeue(String traceId){
        String pop = rightPop(DDFEIYU_TRACE_LOG_QUEUE_KEY, traceId);
        if (!StringUtils.isEmpty(pop)){
            log.info("---[3]日志出队traceId:[ {} ] -> log:[ {} ]", traceId , pop);
        }
        return pop;
    }

    public long registerServer(String host, int port){
        String key = makeFullKey(DDFEIYU_SERVER_QUEUE,null);
        long len = leftPushAll(key, Arrays.asList(host + ":" + port));
        expire(key, TIMEOUT, TimeUnit.HOURS);
        log.info("---[2]registerServer, host:[ {} ], port:[ {} ] ", key , host , port);
        return len;
    }

    public long unRegisterServer(String host, int port){
        String key = makeFullKey(DDFEIYU_SERVER_QUEUE,null);
        long len = leftPushAll(key, Arrays.asList(host + ":" + port));
        expire(key, TIMEOUT, TimeUnit.HOURS);
        log.info("---[2]registerServer, host:[ {} ], port:[ {} ] ", key , host , port);
        return len;
    }


    /**
     *
     * key ：key名次枚举前缀  + 业务key + key名次枚举后缀
     * @param key key名次枚举
     * @param value
     */
    private void setForString(String key,String value, long timeout, TimeUnit unit) {
        redisTemplate.setEnableTransactionSupport(false);
        log.info("--RedisAutoConfig.redisTemplate---setForString:[ {} ]", redisTemplate.toString());
        redisTemplate.opsForValue().set(key, value,timeout,unit);
    }
    /**
     *
     * key ：key名次枚举前缀  + 业务key + key名次枚举后缀
     * @param prefix key名次枚举
     * @param businessKey
     * @param value
     */
    private void setForString(String prefix, String businessKey,String value, long timeout, TimeUnit unit) {
        String key = makeFullKey(prefix, businessKey);
        log.info("--RedisAutoConfig.redisTemplate---setForString:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        redisTemplate.opsForValue().set(key, value,timeout,unit);
    }

    /**
     * string get
     * @param prefix key名次枚举
     * @param businessKey
     * @return
     */
    private String getForString(String prefix, String businessKey) {
        String key = makeFullKey(prefix, businessKey);
        log.info("--RedisAutoConfig.redisTemplate---getForString:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * string get
     * @param key key名次枚举
     * @return
     */
    private String getForString(String key) {
        log.info("--RedisAutoConfig.redisTemplate---getForString:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.opsForValue().get(key);
    }


    /**
     * 从左边插入一个集合
     * key ：key名次枚举前缀  + 业务key + key名次枚举后缀
     * @param key key名次枚举
     * @param list
     */
    private long leftPushAll(String key, List<String> list) {
        log.info("--RedisAutoConfig.redisTemplate---leftPushAll:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.opsForList().leftPushAll(key, list);
    }

    /**
     * 从左边插入一个集合
     * key ：key名次枚举前缀  + 业务key + key名次枚举后缀
     * @param prefix key名次枚举
     * @param businessKey
     * @param list
     */
    private long leftPushAll(String prefix, String businessKey, List<String> list) {
        log.info("--RedisAutoConfig.redisTemplate---leftPushAll:[ {} ]", redisTemplate.toString());
        String key = makeFullKey(prefix,businessKey);
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.opsForList().leftPushAll(key, list);
    }



    /**
     * 从右边移除一个
     * key ：key名次枚举前缀  + 业务key + key名次枚举后缀
     * @param prefix key名次枚举
     * @param businessKey
     */
    private String rightPop(String prefix, String businessKey) {
        log.info("--RedisAutoConfig.redisTemplate---rightPop:[ {} ]", redisTemplate.toString());
        String key = makeFullKey(prefix,businessKey);
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * Redis Smembers 命令返回集合中的所有的成员。 不存在的集合 key 被视为空集合。
     * key ：key名次枚举前缀
     * @param key key名次枚举
     *
     */
    public Set<String> getAllSet(String key) {
        log.info("--RedisAutoConfig.redisTemplate---leftPushAll:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * Redis Sadd 命令将一个或多个成员元素加入到集合中，已经存在于集合的成员元素将被忽略。

     假如集合 key 不存在，则创建一个只包含添加的元素作成员的集合。

     当集合 key 不是集合类型时，返回一个错误。

     注意：在 Redis2.4 版本以前， SADD 只接受单个成员值。
     * key ：key名次枚举前缀
     * @param key key名次枚举
     *
     */
    public long add2Set(String key, String... valus) {
        log.info("--RedisAutoConfig.redisTemplate---leftPushAll:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        Long add = redisTemplate.opsForSet().add(key, valus);
        expire(key, TIMEOUT, TimeUnit.MINUTES);
        return add;
    }

    /**
     * Redis Srem 命令用于移除集合中的一个或多个成员元素，不存在的成员元素会被忽略。

     * 当 key 不是集合类型，返回一个错误。

     * 在 Redis 2.4 版本以前， SREM 只接受单个成员值。
     * @param key
     * @return
     */
    public long removeFromSet(String key, String... valus) {
        log.info("--RedisAutoConfig.redisTemplate---leftPushAll:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        Long remove = redisTemplate.opsForSet().remove(key, valus);
        return remove;
    }

    /**
     * 过期
     * @param prefix
     * @param businessKey
     * @param timeout
     * @param unit
     * @return
     */
    private Boolean expire(String prefix, String businessKey, long timeout, TimeUnit unit){
        log.info("--RedisAutoConfig.redisTemplate---expire:[ {} ]", redisTemplate.toString());
        String key = makeFullKey(prefix,businessKey);
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 过期
     * @param key
     * @param timeout
     * @param unit
     * @return
     */
    private Boolean expire(String key, long timeout, TimeUnit unit){
        log.info("--RedisAutoConfig.redisTemplate---expire:[ {} ]", redisTemplate.toString());
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate.expire(key, timeout, unit);
    }


    private String makeFullKey(String prefix, String businessKey){
        return  prefix + (Objects.isNull(businessKey) ? "" : businessKey);
    }



}
